package com.napenalki.toto.dao.jpa;

import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.napenalki.toto.dao.MatchDao;
import com.napenalki.toto.domain.Match;
import com.napenalki.toto.domain.Stages;

@Transactional
@Repository
public class JpaMatchDao implements MatchDao {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public Match addMatch(Match match) {
        entityManager.persist(match);
        return match;
    }

    @Override
    public Match findMatchById(int id) {
        return entityManager.find(Match.class, id);
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Match> findAllMatches() {
        Query query = entityManager.createQuery("SELECT m FROM Match m");
        return query.getResultList();
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Match> findMatchesByTeam(String teamName) {
        Query query = entityManager.createQuery("SELECT m FROM Match m "
                + "WHERE m.team1Name = :teamName OR "
                + "m.team2Name = :teamName");
        query.setParameter("teamName", teamName);
        return query.getResultList();
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Match> findMatchesByStage(Stages stage) {
        Query query = entityManager.createQuery("SELECT m FROM Match m "
                + "WHERE m.stage = :stage");
        query.setParameter("stage", stage);
        return query.getResultList();
    }

    @Override
    public Match findMatchByTeamsAndStage(String team1Name, String team2Name,
            Stages stage) {
        Query query = entityManager.createQuery("SELECT m FROM Match m "
                + "WHERE m.team1Name = :team1Name AND "
                + "m.team2Name = :team2Name AND m.stage = :stage");
        query.setParameter("team1Name", team1Name);
        query.setParameter("team2Name", team2Name);
        query.setParameter("stage", stage);

        try {
            return (Match) query.getSingleResult();
        } catch (NoResultException nre) {
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Match> findAllFinishedMatches() {
        Query query = entityManager
                .createQuery("SELECT m FROM Match m WHERE m.result IS NOT NULL");
        return query.getResultList();
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<Match> findMatchesByDate(int year, int month, int day) {
        Date thisDayStart = new GregorianCalendar(year, month, day, 0, 0)
                .getTime();
        Date thisDayEnd = new GregorianCalendar(year, month, day, 23, 59)
                .getTime();
        Query query = entityManager
                .createQuery("SELECT m FROM Match m WHERE m.date > :startDate "
                        + "AND m.date < :endDate");
        query.setParameter("startDate", thisDayStart);
        query.setParameter("endDate", thisDayEnd);

        return query.getResultList();
    }

    @Override
    public Match updateMatch(Match match) {
        Match matchx = findMatchById(match.getId());

        if (matchx == null) {
            entityManager.persist(match);
            return match;
        } else {
            matchx.setDate(match.getDate());
            matchx.setLocked(match.isLocked());
            matchx.setTeam1Name(match.getTeam1Name());
            matchx.setTeam2Name(match.getTeam2Name());
            matchx.setResult(match.getResult());
            matchx.setStage(match.getStage());
            matchx.setPredictions(match.getPredictions());
            entityManager.merge(matchx);
            return matchx;
        }
    }

    @Override
    public void deleteMatch(Match deleteMatch) {
        Match matchx = findMatchById(deleteMatch.getId());

        if (matchx != null) {
            entityManager.remove(matchx);
        }
    }

}
